#include "tcp_client.h"

namespace rr {
namespace nio {

TcpClient::TcpClient(EventLoop::Sptr loop)
: loop_(loop)
, socket_(loop->GetIoContextRef())
{
    printf("TcpClient::TcpClient %p\n", this);
}

TcpClient::~TcpClient()
{
    printf("TcpClient::~TcpClient %p\n", this);
}

int32_t TcpClient::Start(int32_t time_out_ms)
{
    try
    {
        auto self = shared_from_this();
        timer_ = std::make_shared<boost::asio::steady_timer>(loop_->GetIoContextRef(), std::chrono::milliseconds{time_out_ms});
        auto time_handler = [self](const boost::system::error_code &ec) {
            if(ec) {
                return;
            }
            printf("TcpClient::OnConnect timeout\n");
            self->OnConnect(boost::system::errc::make_error_code(boost::system::errc::timed_out));
            try
            {
                self->socket_.close();
            }
            catch(const std::exception& e)
            {
            }
        };
        timer_->async_wait(time_handler);

        auto connect_handler = [self](const boost::system::error_code &ec) {
            self->OnConnect(ec);
            try
            {
                self->timer_->cancel();
            }
            catch(const std::exception& e)
            {
                printf("TcpClient::OnConnect timer cancel exception: %s\n", e.what());
            }
        };
        boost::asio::ip::tcp::endpoint ep(boost::asio::ip::make_address("10.10.30.173"), 16789);
        socket_.async_connect(ep, connect_handler);
    }
    catch(const std::exception& e)
    {
        printf("TcpClient::Start exception: %s\n", e.what());
        return -1;
    }
    
    return 0;
}

void TcpClient::Stop()
{
    try
    {
        if(conn_) {
            conn_->DoClose();
        }
        if(socket_.is_open()) {
            socket_.close();
        }
        if(timer_) {
            timer_.reset();
        }
    }
    catch(const std::exception& e)
    {
        printf("TcpClient::Stop exception: %s\n", e.what());
    }
}

void TcpClient::OnConnect(const boost::system::error_code& error)
{
    if(error) {
        printf("TcpClient::OnConnect error: %s\n", error.message().c_str());
        if(connection_cb_) {
            connection_cb_(nullptr);
        }
        connection_cb_ = nullptr;
        return;
    }

    printf("TcpClient::OnConnect success\n");
    conn_ = std::make_shared<TcpConnection>(loop_, socket_);
    conn_->SetConnectionCallback(connection_cb_);
    conn_->SetCloseCallback(close_cb_);
    conn_->SetConnectSuccess();

    return;
}

} //namespace 
} //namespace 
